﻿using System;
using System.Xml.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Newtonsoft.Json
{
    /// <summary>
    /// 针对<see langword="System.Text.Json"/>进行扩展
    /// </summary>
    /// <creator>marc</creator>
    public static class JsonExtensions
    {
        /// <summary>
        /// 判断一个字符串是否是有效的json格式
        /// </summary>
        /// <param name="str">待判断的字符串</param>
        /// <returns>若字符串是有效json，则返回<see langword="true"/>，反之<see langword="false"/></returns>
        public static bool IsJson(this string str)
        {
            try
            {
                JToken.Parse(str);
                return true;
            }
            catch (JsonReaderException)
            {
                return false;
            }
        }

        /// <summary>
        /// 将对象序列化为 JSON 字符串。
        /// </summary>
        /// <param name="obj">要序列化为JSON的对象。</param>
        public static string ToJson<T>(this T obj)
        {
            return JsonConvert.SerializeObject(obj);
        }

        /// <summary>
        /// 将对象序列化为 JSON 字符串。
        /// </summary>
        /// <param name="obj">要序列化为JSON的对象。</param>
        /// <param name="options">在反序列化过程中使用的 JsonSerializerOptions。</param>
        public static string ToJson<T>(this T obj, JsonSerializerSettings options)
        {
            return JsonConvert.SerializeObject(obj, options);
        }

        /// <summary>
        /// 将 JSON 字符串反序列化为指定类型的对象。
        /// </summary>
        public static T FromJson<T>(this string json)
        {
            return JsonConvert.DeserializeObject<T>(json);
        }


        /// <summary>
        /// 将 JSON 字符串反序列化为指定类型的对象。
        /// </summary>
        /// <param name="json">要反序列化的 JSON 字符串。</param>
        /// <param name="options">在反序列化过程中使用的 JsonSerializerOptions。</param>
        public static T FromJson<T>(this string json, JsonSerializerSettings options)
        {
            return JsonConvert.DeserializeObject<T>(json, options);
        }

        /// <summary>
        /// 将 JSON 字符串反序列化为动态对象。
        /// </summary>
        public static dynamic FromJson(this string json)
        {
            return JsonConvert.DeserializeObject<dynamic>(json);
        }

        /// <summary>
        /// 将 JSON 字符串反序列化为动态对象。
        /// </summary>
        /// <param name="json">要反序列化的 JSON 字符串。</param>
        /// <param name="options">在反序列化过程中使用的 JsonSerializerOptions。</param>
        public static dynamic FromJson(this string json, JsonSerializerSettings options)
        {
            return JsonConvert.DeserializeObject<dynamic>(json, options);
        }

        /// <summary>
        /// 将JSON字符串转换为XML字符串
        /// </summary>
        /// <param name="json">要反序列化的 JSON 字符串。</param>
        public static string JsonToXmlString(this string json)
        {
            JObject jsonObject = JObject.Parse(json);
            XNode node = JsonConvert.DeserializeXNode(jsonObject.ToString(), "root");
            return node.ToString();
        }

        /// <summary>
        /// 将 JSON 转换为 XML
        /// </summary>
        /// <param name="jsonObject">json对象</param>
        /// <returns></returns>
        public static XDocument ToXml(this JObject jsonObject)
        {
            // 创建 XML 文档
            XDocument xmlDocument = new XDocument();

            // 添加根元素
            var root = new XElement("root");
            xmlDocument.Add(root);

            // 将 JSON 对象转换为 XML 元素并添加到根元素
            ConvertJObjectToXml(jsonObject, root);

            return xmlDocument;
        }

        /// <summary>
        /// 将 JSON 转换为 XML 字符串
        /// </summary>
        /// <param name="jsonObject">json对象</param>
        /// <returns></returns>
        public static string ToXmlString(this JObject jsonObject)
        {
            return ToXml(jsonObject).ToString();
        }

        /// <summary>
        /// 将 JSON 对象转换为 XML 元素
        /// </summary>
        /// <param name="jsonObject">json对象</param>
        /// <param name="parent">父级元素</param>
        private static void ConvertJObjectToXml(JObject jsonObject, XElement parent)
        {
            foreach (var property in jsonObject.Properties())
            {
                if (property.Value.Type == JTokenType.Object)
                {
                    // 如果属性值是 JSON 对象，则递归转换为 XML 元素
                    var childElement = new XElement(property.Name);
                    parent.Add(childElement);
                    ConvertJObjectToXml((JObject)property.Value, childElement);
                }
                else if (property.Value.Type == JTokenType.Array)
                {
                    // 如果属性值是 JSON 数组，则将每个元素转换为 XML 元素
                    foreach (var item in (JArray)property.Value)
                    {
                        var childElement = new XElement(property.Name);
                        parent.Add(childElement);
                        ConvertJTokenToXml(item, childElement);
                    }
                }
                else
                {
                    // 如果属性值是基本类型，则直接添加为 XML 属性
                    parent.Add(new XAttribute(property.Name, property.Value));
                }
            }
        }

        /// <summary>
        /// 将 JSON 值转换为 XML 元素
        /// </summary>
        /// <param name="token">jToken对象</param>
        /// <param name="parent">父级元素</param>
        private static void ConvertJTokenToXml(JToken token, XElement parent)
        {
            if (token.Type == JTokenType.Object)
            {
                ConvertJObjectToXml((JObject)token, parent);
            }
            else if (token.Type == JTokenType.Array)
            {
                foreach (var item in (JArray)token)
                {
                    ConvertJTokenToXml(item, parent);
                }
            }
            else
            {
                parent.Add(token);
            }
        }

        /// <summary>
        /// 获取JSON对象中指定键的值
        /// </summary>
        /// <param name="jsonObject">json对象</param>
        /// <param name="key">键</param>
        /// <returns></returns>
        public static JToken GetValue(this JObject jsonObject, string key)
        {
            return jsonObject.TryGetValue(key, out var value) ? value : null;
        }

        /// <summary>
        /// 尝试获取JSON对象中指定键的值，并将其转换为指定类型
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="jsonObject">json对象</param>
        /// <param name="key">键</param>
        /// <returns></returns>
        public static T GetValue<T>(this JObject jsonObject, string key)
        {
            var value = jsonObject.GetValue(key);
            return value != null ? value.ToObject<T>() : default;
        }

        /// <summary>
        /// 设置 JSON 对象中指定键的值
        /// </summary>
        /// <param name="jsonObject">json对象</param>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        public static void SetValue(this JObject jsonObject, string key, JToken value)
        {
            jsonObject[key] = value;
        }

        /// <summary>
        /// 设置 JSON 对象中指定键的值（从字符串）
        /// </summary>
        /// <param name="jsonObject">json对象</param>
        /// <param name="key">镇</param>
        /// <param name="jsonValue">json字符串</param>
        public static void SetValue(this JObject jsonObject, string key, string jsonValue)
        {
            jsonObject[key] = JToken.Parse(jsonValue);
        }

        /// <summary>
        /// 设置 JSON 对象中指定键的值（从对象）
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="jsonObject">json对象</param>
        /// <param name="key">键</param>
        /// <param name="obj">值</param>
        public static void SetValue<T>(this JObject jsonObject, string key, T obj)
        {
            jsonObject[key] = JToken.FromObject(obj);
        }

        /// <summary>
        /// 设置 JSON 对象中指定键的值（从匿名对象）
        /// </summary>
        /// <param name="jsonObject">json对象</param>
        /// <param name="key">键</param>
        /// <param name="obj">值</param>
        public static void SetValue(this JObject jsonObject, string key, object obj)
        {
            jsonObject[key] = JToken.FromObject(obj);
        }

        /// <summary>
        /// 将json字符串格式化为美观的字符串
        /// </summary>
        /// <param name="json">待格式化的json字符串</param>
        /// <returns></returns>
        public static string FormatJson(this string json)
        {
            JToken parsedJson = JToken.Parse(json);

            string formattedJson = parsedJson.ToString(Formatting.Indented);
            return formattedJson;
        }

        /// <summary>
        /// 将JToken对象格式化为美观的字符串
        /// </summary>
        /// <param name="json">待格式化的JToken对象</param>
        /// <returns></returns>
        public static string FormatJson(this JToken json)
        {
            string formattedJson = json.ToString(Formatting.Indented);
            return formattedJson;
        }
    }
}
